<?php
/**
 * Created by PhpStorm.
 * User: cephei
 * Date: 10/16/15
 * Time: 4:25 PM
 */

namespace App\Http\Practice\Lib;

use Throwable;

class ArithmeticLib
{
    static function getArithmeticList($count = 4, $allowQuote = true, $requireQuote = false, $numRange = [[2, 99], [2, 99], [2, 99], [2, 99]], $resultRange = [2, 99], $allowDecimal = false, $requireDecimal = false, $operators = ['+', '-', '*', '/'], $requiredOperators = ['*', '/'])
    {
        $level = count($numRange);
        $formulaList = array();
        for ($z = 0; $z < $count; $z++) {
            while (true) {
                $formula = rand($numRange[0][0], $numRange[0][1]);
                for ($i = 0; $i < $level - 1; $i++) {
                    $errorCount1 = 0;
                    while (true) {
                        if (++$errorCount1 > 100) {
                            continue 3;
                        }
                        $quoteNum = rand(0, $level - 1 - $i);
                        $quoteNum = $allowQuote ? $quoteNum : 0;
                        if ($quoteNum == 1) {
                            continue;
                        }
                        if ($quoteNum == 0) {
                            // TODO 除数保持1位数特殊处理
                            $toperator = self::randomOperator($operators);
                            $tFormula = sprintf('%s%s%d', $formula, $toperator, $toperator == '/' ? rand(2, 9) : rand($numRange[$i + 1][0], $numRange[$i + 1][1]));
                            if (self::validateResult($tFormula, $resultRange, $allowDecimal, $requireDecimal)) {
                                $formula = $tFormula;
                                break;
                            }
                        } else {
                            $formula2 = rand($numRange[$i + 1][0], $numRange[$i + 1][1]);
                            for ($j = 0; $j < $quoteNum - 1; $j++) {
                                $errorCount2 = 0;
                                while (true) {
                                    if (++$errorCount2 > 100) {
                                        continue 5;
                                    }
                                    // TODO 除数保持1位数特殊处理
                                    $toperator = self::randomOperator($operators);
                                    $tFormula2 = sprintf('%s%s%d', $formula2, $toperator, $toperator == '/' ? rand(2, 9) : rand($numRange[$i + 1 + $j + 1][0], $numRange[$i + 1 + $j + 1][1]));
                                    if (self::validateResult($tFormula2, $resultRange, $allowDecimal, $requireDecimal)) {
                                        $formula2 = $tFormula2;
                                        break;
                                    }
                                }
                            }
                            // TODO 除数保持1位数特殊处理
                            $toperator = self::randomOperator($operators);
                            if ($toperator == '/') {
                                $tresult = self::getResult($formula2);
                                if ($tresult > 10) {
                                    continue;
                                }
                            }
                            $tFormula = sprintf('%s%s(%s)', $formula, $toperator, $formula2);
                            if (self::validateResult($tFormula, $resultRange, $allowDecimal, $requireDecimal)) {
                                $formula = $tFormula;
                                $i += $quoteNum - 1;
                                break;
                            }
                        }

                    }
                }

                if (self::validateFormula($formula, $requireQuote, $requiredOperators)) {
                    $transformedFormula = self::format($formula);
                    foreach ($formulaList as $f) {
                        if ($f == $transformedFormula) {
                            continue 2;
                        }
                    }
                    $formulaList[] = $transformedFormula;
                    break;
                }
            }
        }
        return $formulaList;
    }

    private static function getResult($formula)
    {
        $statement = sprintf('return %s;', $formula);
        try {
            return eval($statement);
        } catch (Throwable $e) {
            return false;
        }
    }

    private static function validateResult($formula, $resultRange, $allowDecimal, $requireDecimal)
    {
        $result = self::getResult($formula);
        if ($result === false) {
            return false;
        } else if ($result > $resultRange[1] || $result < $resultRange[0]) {
            return false;
        } else if (!$allowDecimal && !is_int($result)) {
            return false;
        } else if ($requireDecimal && is_int($result)) {
            return false;
        } else {
            return true;
        }
    }

    private static function validateFormula($formula, $requireQuote, $requiredOperators = ['*', '/'])
    {
        $isvalid = false;
        foreach ($requiredOperators as $operator) {
            $isvalid = $isvalid || strpos($formula, $operator);
            if ($isvalid) {
                break;
            }
        }
        if ($requireQuote) {
            if (!strpos($formula, '(')) {
                $isvalid = false;
            }
        }
        return $isvalid;
    }

    private static function randomOperator($operators = ['+', '-', '*', '/'])
    {
        return $operators[rand(0, count($operators) - 1)];
    }

    private static function format($formula)
    {
        $formula = str_replace(['+', '-', '*', '/'], [' + ', ' - ', ' x ', ' ÷ '], $formula);
        $formula .= ' = ';
        return $formula;
    }
}